package com.ycl.election;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ElectionHandler extends ChannelInboundHandlerAdapter {
    private final ElectionNode node;

    public ElectionHandler(ElectionNode node) {
        this.node = node;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ElectionMessage electionMessage = (ElectionMessage) msg;
        System.out.println("Node " + node.getNodeId() + " received: " + electionMessage);

        if (electionMessage.getType() == ElectionMessage.MessageType.VOTE_REQUEST) {
            // 判断是否是否接受投票信息。只有在主节点没确定并且zxId较大时，才发送投票消息
            // 如果接受了投票请求的话，则更新本地的投票逻辑，然后给投票节点发送接受投票的消息
            if (electionMessage.getZxId() >= node.getZxId() && node.getLeaderId() == 0) {
                node.receiveVote(electionMessage.getNodeId());
                ElectionMessage voteMessage = new ElectionMessage(ElectionMessage.MessageType.VOTE, electionMessage.getNodeId(), electionMessage.getZxId(), electionMessage.getNodeId());
                ctx.writeAndFlush(voteMessage);
            } else {
                // 如果已经确定主节点了，直接发送ELECTED消息
                sendLeaderInfo(ctx);
            }
        } else if (electionMessage.getType() == ElectionMessage.MessageType.VOTE) {
            // 如果投票消息被接受了，则更新本地的投票逻辑。
            if (electionMessage.getZxId() >= node.getZxId() && node.getLeaderId() == 0) {
                node.receiveVote(electionMessage.getNodeId());
            } else {
                // 如果已经确定主节点了，直接发送ELECTED消息
                sendLeaderInfo(ctx);
            }
        } else if (electionMessage.getType() == ElectionMessage.MessageType.ELECTED) {
            if (node.getLeaderId() == 0) {
                node.setLeaderId(electionMessage.getVoteFor());
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 发送主节点信息
     *
     * @param ctx
     */
    private void sendLeaderInfo(ChannelHandlerContext ctx) {
        // 已经确定有主节点了，那直接发送ELECTED消息
        ElectionNode leaderNode = Constant.nodeMap.get(node.getLeaderId());
        ElectionMessage voteMessage = new ElectionMessage(ElectionMessage.MessageType.ELECTED, leaderNode.getLeaderId(), leaderNode.getZxId(), leaderNode.getLeaderId());
        ctx.writeAndFlush(voteMessage);
    }
}
